package main

import (
	"bufio"
	"context"
	"crypto"
	"crypto/ed25519"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"reflect"
	"regexp"
	"sync"
	"syscall"
	"time"
	"unicode/utf8"

	"gitee.com/xy02/yrm"
	b "github.com/dgraph-io/badger/v4"
	"github.com/dgraph-io/badger/v4/y"
	"github.com/fxamacker/cbor/v2"
	"github.com/vmihailenco/msgpack/v5"

	"github.com/plgd-dev/go-coap/v3/message"
	"github.com/plgd-dev/go-coap/v3/message/pool"
	"github.com/plgd-dev/go-coap/v3/udp"
)

type SimpleFlow[M any] struct {
	msgChannel chan M
	errChan    chan error
	cancel     func()
}

type Node struct {
	Data int
	Next *Node
}

func main() {
	startTime := time.Now()
	testReverseNode()
	// testBadger()
	// testGenType(SimpleFlow[int]{}, &yrm.Ctx[SimpleFlow[int]]{})
	// testBroadcast()
	// testHttpServer()
	// testSendOrDrop()
	// testSelect()
	// testSyncMap()
	// testScanner()
	// testCBOR()
	// TestEd25519()
	// startChild3()
	// ioPipe()
	// childPipe()
	// tcpProxy()
	// testDefer(1)
	// testJSONDecoder()
	// testGrep()
	// cost := time.Since(startTime) / time.Second * time.Second
	cost := time.Since(startTime)
	fmt.Println("total cost", cost)
	log.Println("the end")
	// panic("something wrong")
}

func testReverseNode() {
	head := Node{
		Data: 1,
	}
	node2 := Node{
		Data: 2,
	}
	node3 := Node{
		Data: 3,
	}
	node4 := Node{
		Data: 4,
	}
	head.Next = &node2
	node2.Next = &node3
	node3.Next = &node4
	log.Println("old")
	logNode(&head)
	log.Println("reverse")
	r := reverseNode(nil, &head)
	logNode(r)
	log.Println("old")
	logNode(&head)
}

func logNode(node *Node) {
	if node == nil {
		return
	}
	fmt.Println(node.Data)
	logNode(node.Next)
}

func reverseNode(prev *Node, node *Node) *Node {
	if node == nil {
		return prev
	}
	next := node.Next
	newNode := *node
	newNode.Next = prev
	return reverseNode(&newNode, next)
}

func testCoap() {
	sync := make(chan bool)
	co, err := udp.Dial("localhost:5688")
	if err != nil {
		log.Fatalf("Error dialing: %v", err)
	}
	num := 0
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	obs, err := co.Observe(ctx, "/some/path", func(req *pool.Message) {
		log.Printf("Got %+v\n", req)
		req.Observe()
		num++
		if num >= 10 {
			sync <- true
		}
	}, message.Option{})
	if err != nil {
		log.Fatalf("Unexpected error '%v'", err)
	}
	<-sync
	ctx, cancel = context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	obs.Cancel(ctx)
}

func testBadger() {
	db, err := b.Open(b.DefaultOptions("main.Test"))
	if err != nil {
		panic(err)
	}
	defer func() { y.Check(db.Close()) }()
	log.Println("len", len(db.Tables()))
	// s, err := db.GetSequence([]byte("test"), 1)
	// log.Println(s, err)

	// log.Println(s.Next())
	// log.Println(s.Release())
	// log.Println(s.Next())
	// err = db.View(func(txn *b.Txn) error {
	// 	_, err := txn.Get([]byte("key"))
	// 	// We expect ErrKeyNotFound
	// 	fmt.Println(err)
	// 	return nil
	// })

	typeID := make([]byte, 4)
	err = db.Update(func(txn *b.Txn) error {
		key := []byte("type:B")
		item, err := txn.Get(key)
		if err == b.ErrKeyNotFound {
			s, err := db.GetSequence([]byte("typeID"), 1)
			log.Println(s, err)
			id, err := s.Next()
			if err != nil {
				return err
			}
			binary.BigEndian.PutUint32(typeID, uint32(id))
			return txn.Set(key, typeID)
		}
		if err != nil {
			return err
		}
		_, err = item.ValueCopy(typeID)
		return err
	})
	if err != nil {

	}
	log.Printf("%#v", typeID)
}

func testGenType[T any](msg T, c *yrm.Ctx[T]) {
	reg := regexp.MustCompile(`func\((\S+)\)`)

	k := reflect.TypeOf(msg).Kind()
	log.Printf("kind:%s, t: %T, c: %T, v:%v\n", k, msg, c.Broadcast, reg.FindStringSubmatch(fmt.Sprintf("%T", c.Broadcast)))
}

func testTicker() {
	ticker := time.NewTicker(time.Second)
	defer ticker.Stop()
	done := make(chan bool)
	go func() {
		time.Sleep(10 * time.Second)
		done <- true
	}()
	for {
		select {
		case <-done:
			fmt.Println("Done!")
			return
		case t := <-ticker.C:
			fmt.Println("Current time: ", t)
		}
	}
}

// func testContext() {
// 	ctx0 := context.Background()
// 	ctxParent, _ := context.WithCancel(ctx0)
// 	ctxChild, cancelChild := context.WithCancel(ctx0)
// 	ctx1, c1 := context.WithCancel(ctx0)
// }

type DropableSender interface {
	Send(any)
	GetReplyChannel() <-chan any
	DecrementProcessing()
	//获取正在处理的消息数量
	GetProcessing() int
}

func testBroadcast() {
	reader := make(chan int, 100)
	go func(n int) {
		//moke 2 slow consumer
		ch1 := make(chan int, n)
		ch1Replier := runSubscriber("A", ch1, 100*time.Millisecond)
		ch1InProgress := 0
		ch2 := make(chan int, n)
		ch2Replier := runSubscriber("B", ch2, 500*time.Millisecond)
		ch2InProgress := 0
		for {
			select {
			case x := <-reader:
				if ch1InProgress < n {
					ch1 <- x
					ch1InProgress++
				}
				if ch2InProgress < n {
					ch2 <- x
					ch2InProgress++
				}
			case <-ch1Replier:
				ch1InProgress--
			case <-ch2Replier:
				ch2InProgress--
			}
		}

	}(1)
	i := 0
	for {
		reader <- i
		i++
		// log.Println("SEND", i)
		time.Sleep(10 * time.Millisecond)
	}
}

func runSubscriber(name string, reader <-chan int, d time.Duration) <-chan any {
	replier := make(chan any, 1)
	go func() {
		for x := range reader {
			log.Println(name, "recv", x)
			x++
			time.Sleep(d)
			replier <- nil
		}
	}()
	return replier
}

type apiHandler struct{}

func (apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Welcome to api!")
}

func testHttpServer() {
	mux := http.NewServeMux()
	mux.Handle("/api/", apiHandler{})
	mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		// The "/" pattern matches everything, so we need to check
		// that we're at the root here.
		if req.URL.Path != "/" {
			log.Println(req.URL.Path)
			http.NotFound(w, req)
			return
		}
		fmt.Fprintf(w, "Welcome to the home page!")
	})
	server := http.Server{
		Addr:    ":8080",
		Handler: mux,
	}
	time.AfterFunc(5*time.Second, func() {
		mux.HandleFunc("/api2", func(w http.ResponseWriter, req *http.Request) {
		})
	})
	server.ListenAndServe()
}

func testSendOrDrop() {
	send := startSendLoop(context.Background(), 5)
	i := 0
	for {
		i++
		send(Msg{SN: i})
		time.Sleep(50 * time.Millisecond)
	}
}

type Msg struct {
	SN int
}

type SendOrDrop func(msg Msg)

func startSendLoop(ctx context.Context, chanSize int) SendOrDrop {
	msgChan := make(chan Msg, chanSize)
	inProgress := 0
	mu := sync.RWMutex{}
	go func() {

		for {
			select {
			case <-ctx.Done():
				// writer.End(ctx.Err())
				return
			case msg := <-msgChan:
				// if inProgress == chanSize {
				// 	//drop msg
				// 	log.Println("drop", msg.SN)
				// 	continue
				// }
				// inProgress++
				// log.Println("msg.SN", msg.SN, "inProgress++", inProgress)
				//writer.Wirte(msg)
				time.Sleep(2 * time.Second)
				log.Println("sent msg.SN", msg.SN)
				mu.Lock()
				inProgress--
				log.Println("msg.SN", msg.SN, "inProgress--", inProgress)
				mu.Unlock()
			}
		}
	}()
	return func(msg Msg) {
		// log.Println("test")
		isFull := false
		mu.RLock()
		isFull = inProgress == chanSize
		mu.RUnlock()
		if isFull {
			log.Println("drop", msg.SN)
			return
		}
		mu.Lock()
		inProgress++
		log.Println("msg.SN", msg.SN, "inProgress++", inProgress)
		mu.Unlock()
		msgChan <- msg
	}
}

func testSelect() {
	ch1 := make(chan int, 10)
	ch2 := make(chan int, 10)

	ch3 := make(chan int, 1)
	b := make(chan int, 1)
	go func() {
		// time.Sleep(time.Second)
		for {
			select {
			case a := <-ch1:
				log.Println(a)
			case a := <-ch2:
				log.Println(a)
			}
		}
		ch3 <- 0
	}()
	time.Sleep(time.Second)
	go sendToCh(ch1, 1, b)
	go sendToCh(ch2, 2, b)
	go sendToCh(ch1, 11, b)
	go sendToCh(ch2, 22, b)
	close(b)
	// ch1 <- 1
	// ch2 <- 2
	// ch1 <- 11
	// ch2 <- 22
	<-ch3
}
func sendToCh(ch chan int, i int, b chan int) {
	<-b
	ch <- i
}

func testSyncMap() {
	a := sync.Map{}
	m := Map{
		m: a,
	}
	a.Store(0, "x")
	log.Println(m.m.Load(0))
	log.Println(a.Load(0))
	log.Println("==", &a == &m.m)
	m.write(&m.m)
	log.Println("test read1")
	log.Println(m.m.Load(1))
	log.Println("test read2")
	log.Println(m.read(&m.m))
}

type Map struct {
	m sync.Map
}

func (x Map) write(a *sync.Map) {
	log.Println("x.m == a", &x.m == a)
	x.m.Store(1, "a")
	log.Printf("p:%p\n", x.m)
	log.Println(x.read(&x.m))
}

func (x Map) read(b *sync.Map) (value any, ok bool) {
	log.Printf("p:%p,x.m == b :%v \n", x.m, &x.m == b)
	return x.m.Load(1)
}

func testScanner() {
	// const input = "   1234 5678 1234567901234567890"
	// r := strings.NewReader(input)
	r := &Test{
		data: []byte(`   1234 5678 99`),
	}
	scanner := bufio.NewScanner(r)
	// Create a custom split function by wrapping the existing ScanWords function.
	// split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
	// 	l := len(data)
	// 	if l == 0 {
	// 		return 0, nil, nil
	// 	}
	// 	advance = 3
	// 	if l < advance {
	// 		// token = data[:l]
	// 		advance = l
	// 		// err = bufio.ErrFinalToken
	// 		// err = io.EOF
	// 		// return
	// 	}
	// 	token = data[:advance]
	// 	advance, token, err = bufio.ScanWords(data, atEOF)
	// 	// if err == nil && token != nil {
	// 	// 	_, err = strconv.ParseInt(string(token), 10, 32)
	// 	// }
	// 	return
	// }
	// split := bufio.ScanWords
	split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
		// Skip leading spaces.
		start := 0
		for width := 0; start < len(data); start += width {
			var r rune
			r, width = utf8.DecodeRune(data[start:])
			if !isSpace(r) {
				break
			}
		}
		// Scan until space, marking end of word.
		for width, i := 0, start; i < len(data); i += width {
			var r rune
			r, width = utf8.DecodeRune(data[i:])
			if isSpace(r) {
				println(1, start, len(data))
				return i + width, data[start:i], nil
			}
		}
		// If we're at EOF, we have a final, non-empty, non-terminated word. Return it.
		if atEOF && len(data) > start {
			println(2, start, len(data))
			return len(data), data[start:], nil
		}
		// Request more data.
		println(3, start, data)
		return start, nil, nil
	}
	// Set the split function for the scanning operation.
	scanner.Split(split)
	// Validate the input
	for scanner.Scan() {
		t := scanner.Text()
		fmt.Printf("%s, LEN:%d\n", t, len(t))
	}

	if err := scanner.Err(); err != nil {
		fmt.Printf("Invalid input: %s\n", err)
	}
	// scanner := bufio.NewScanner(strings.NewReader(input))
	// log.Println(bufio.ScanWords([]byte(input), false))
	// log.Println(input)
}

func isSpace(r rune) bool {
	if r <= '\u00FF' {
		// Obvious ASCII ones: \t through \r plus space. Plus two Latin-1 oddballs.
		switch r {
		case ' ', '\t', '\n', '\v', '\f', '\r':
			return true
		case '\u0085', '\u00A0':
			return true
		}
		return false
	}
	// High-valued ones.
	if '\u2000' <= r && r <= '\u200a' {
		return true
	}
	switch r {
	case '\u1680', '\u2028', '\u2029', '\u202f', '\u205f', '\u3000':
		return true
	}
	return false
}

func testCBOR() {
	x := []interface{}{
		"app",
		[]byte{1, 2},
	}
	b, _ := cbor.Marshal(x)
	log.Printf("b: %#v\n", b)
}

func TestMsgPack() {
	test := Test{
		data: []byte{
			0x81, 0xa3, 0x41, 0x67, 0x65, 18,
		},
		i:   0,
		Age: 18,
	}
	b, _ := msgpack.Marshal(&test)
	log.Printf("b: %x\n", b)
	test.data = b
	d := msgpack.NewDecoder(&test)
	err := d.Decode(&test)
	log.Println(err, test)
	// err = d.Decode(&test)
	// log.Println(err, test)
}

// 得到64字节签名长度
func TestEd25519() {
	seed := [32]byte{}
	privateKey := ed25519.NewKeyFromSeed(seed[:])
	message := []byte("message to be signed")
	signature := ed25519.Sign(privateKey, message)
	fmt.Printf("Signature: len:%v, %x\n", len(signature), signature)

}

// 得到256字节签名长度
func TestRSASign() {
	rng := rand.Reader
	rsaPrivateKey, _ := rsa.GenerateKey(rng, 2048)
	message := []byte("message to be signed")

	// Only small messages can be signed directly; thus the hash of a
	// message, rather than the message itself, is signed. This requires
	// that the hash function be collision resistant. SHA-256 is the
	// least-strong hash function that should be used for this at the time
	// of writing (2016).
	hashed := sha256.Sum256(message)

	signature, err := rsa.SignPKCS1v15(rng, rsaPrivateKey, crypto.SHA256, hashed[:])
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error from signing: %s\n", err)
		return
	}

	fmt.Printf("Signature: len:%v, %x\n", len(signature), signature)
}

type Test struct {
	Age  int `json:"age" msg:"age"`
	data []byte
	i    int
}

func (t *Test) Read(p []byte) (n int, err error) {
	if t.i >= len(t.data) {
		return 0, io.EOF
	}
	// src := []byte(`{"age":18} {"age":20}{`)
	n = copy(p, t.data[t.i:t.i+1])
	t.i++
	// log.Println("n", n)
	time.Sleep(100 * time.Millisecond)
	return
}

func testJSONDecoder() {
	// `{"age":18}{"age":20}`
	test := Test{
		data: []byte(`{"age":18}
     {"age":20}{111`),
		i: 0,
	}
	d := json.NewDecoder(&test)
	err := d.Decode(&test)
	log.Println(err, test)
	err = d.Decode(&test)
	log.Println(err, test)
}

func ttt(err error, b, i int) {
	log.Println(b, i, err)
}

func testDefer(i int) (err error) {
	b := 2
	defer func() {
		ttt(err, b, i)
	}()
	log.Println("start")
	time.Sleep(time.Second)
	b = 3
	i = 10
	err = errors.New("test")
	return
}

func tcpProxy() error {
	ln, err := net.Listen("tcp", ":3306")
	if err != nil {
		// handle error
		return err
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			// handle error
			return err
		}
		go handleConnection(conn)
	}
}

func handleConnection(conn net.Conn) (err error) {
	defer log.Printf("on conn(%p) err:%v\n", conn, err)
	defer conn.Close()
	dconn, err := net.Dial("tcp", "rm-uf6qt9k7rsc19ryd1vo.mysql.rds.aliyuncs.com:3306")
	if err != nil {
		return
	}
	log.Printf("on conn(%p) ok\n", conn)
	go func() {
		io.Copy(dconn, conn)
	}()
	_, err = io.Copy(conn, dconn)
	return err
}

func ioPipe() {
	r, w := io.Pipe()

	go func() {
		fmt.Fprint(w, "some io.Reader stream to be read\n")
		w.Close()
	}()

	if _, err := io.Copy(os.Stdout, r); err != nil {
		log.Fatal(err)
	}
}

func testGrep() {
	cmd := exec.Command("go", "env")
	stdout, err := cmd.StdoutPipe() //cmd.Stdout的值不再是nil
	if err != nil {
		log.Fatal(err)
	}
	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}
	log.Println(cmd.Stdin, cmd.Stdout, cmd.Stderr, stdout)
	grep := exec.Command("grep", "GOROOT")
	grep.Stdin = stdout //设置输入
	grep_out, err := grep.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	if err := grep.Start(); err != nil {
		log.Fatal(err)
	}
	if _, err := io.Copy(os.Stdout, grep_out); err != nil {
		log.Fatal(err)
	}
}

var testSh = `echo hi
echo ih`

func childPipe() {
	// cmd := exec.Command("echo", "hello")
	// cmd := exec.Command("sh", "-c", "go env | grep GOARCH")
	cmd := exec.Command("sh", "-c", testSh)
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	if err := cmd.Start(); err != nil {
		log.Fatal(err)
	}
	if _, err := io.Copy(os.Stdout, stdout); err != nil {
		log.Fatal(err)
	}
}

func startChild3() {
	cmd := exec.Command("/bin/sh", "-c", "sleep 10")
	// cmd := exec.Command("sleep", "10")
	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
	time.AfterFunc(3*time.Second, func() {
		fmt.Println("PID3=", cmd.Process.Pid)
		startTime := time.Now()
		syscall.Kill(-cmd.Process.Pid, syscall.SIGQUIT)
		fmt.Println("killed", time.Since(startTime))
	})
	fmt.Println("begin run")
	startTime := time.Now()
	cmd.Run()
	fmt.Println("finish", time.Since(startTime))
}
